package com.common.file.service;

import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.lang.ObjectId;
import cn.hutool.core.util.StrUtil;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyun.oss.model.PutObjectResult;
import com.common.core.constants.CacheConstants;
import com.common.core.constants.Constants;
import com.common.core.enums.ResultCode;
import com.common.core.utils.ThreadLocalUtil;
import com.common.redis.service.RedisService;
import com.common.security.exception.ServiceException;
import com.common.file.config.OSSProperties;
import com.common.file.domain.OSSResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
@RefreshScope
public class OSSService {

    @Autowired
    private OSSProperties prop;

    @Autowired
    private OSSClient ossClient;

    @Autowired
    private RedisService redisService;

    @Value("${file.max-time}")
    private int maxTime;

    @Value("${file.test}")
    private boolean test;

    public OSSResult uploadFile(MultipartFile file) throws Exception {
        if (!test) {
            checkUploadCount();
        }
        InputStream inputStream = null;
        try {
            String originalFilename = file.getOriginalFilename();
            String fileName;
            if (originalFilename != null && !originalFilename.isEmpty()) {
                fileName = originalFilename.toLowerCase();
            } else {
                fileName = "default.png";
            }
            
            // 提取文件扩展名
            String extName;
            int dotIndex = fileName.lastIndexOf(".");
            if (dotIndex > 0 && dotIndex < fileName.length() - 1) {
                extName = fileName.substring(dotIndex + 1);
            } else {
                extName = "png"; // 默认扩展名
            }
            
            inputStream = file.getInputStream();
            return upload(extName, inputStream);
        } catch (Exception e) {
            log.error("OSS upload file error", e);
            throw new ServiceException(ResultCode.FAILED_FILE_UPLOAD);
        } finally {
            if (inputStream != null) {
                inputStream.close();
            }
        }
    }

    private void checkUploadCount() {
        Long userId = ThreadLocalUtil.get(Constants.USER_ID, Long.class);
        Long times = redisService.getCacheMapValue(CacheConstants.USER_UPLOAD_TIMES_KEY, String.valueOf(userId), Long.class);
        if (times != null && times >= maxTime) {
            throw new ServiceException(ResultCode.FAILED_FILE_UPLOAD_TIME_LIMIT);
        }
        redisService.incrementHashValue(CacheConstants.USER_UPLOAD_TIMES_KEY, String.valueOf(userId), 1);
        if (times == null || times == 0) {
            long seconds = ChronoUnit.SECONDS.between(LocalDateTime.now(),
                    LocalDateTime.now().plusDays(1).withHour(0).withMinute(0).withSecond(0).withNano(0));
            redisService.expire(CacheConstants.USER_UPLOAD_TIMES_KEY, seconds, TimeUnit.SECONDS);
        }
    }

    private OSSResult upload(String fileType, InputStream inputStream) {
        // 构建文件key，确保路径正确
        String pathPrefix = prop.getPathPrefix();
        if (StrUtil.isBlank(pathPrefix)) {
            pathPrefix = "";
        } else {
            // 确保路径前缀以 / 结尾（如果不为空）
            if (!pathPrefix.endsWith("/")) {
                pathPrefix = pathPrefix + "/";
            }
            // 确保路径前缀不以 / 开头
            if (pathPrefix.startsWith("/")) {
                pathPrefix = pathPrefix.substring(1);
            }
        }
        
        // key pattern: pathPrefix/id.xxx
        String key = pathPrefix + ObjectId.next() + "." + fileType;
        
        ObjectMetadata objectMetadata = new ObjectMetadata();
        // 使用后端代理访问，不需要设置 PublicRead
        // objectMetadata.setObjectAcl(CannedAccessControlList.PublicRead);
        PutObjectRequest request = new PutObjectRequest(prop.getBucketName(), key, inputStream, objectMetadata);
        PutObjectResult putObjectResult;
        try {
            putObjectResult = ossClient.putObject(request);
        } catch (Exception e) {
            log.error("OSS put object error: {}", ExceptionUtil.stacktraceToOneLineString(e, 500));
            throw new ServiceException(ResultCode.FAILED_FILE_UPLOAD);
        }
        return assembleOSSResult(key, putObjectResult);
    }

    private OSSResult assembleOSSResult(String key, PutObjectResult putObjectResult) {
        OSSResult ossResult = new OSSResult();
        if (putObjectResult == null || StrUtil.isBlank(putObjectResult.getRequestId())) {
            ossResult.setSuccess(false);
        } else {
            ossResult.setSuccess(true);
            // 返回 key 作为 name
            ossResult.setName(key);
            // 构建完整的下载 URL
            // 格式: https://{bucketName}.{endpoint}/{key}
            String downloadUrl = buildDownloadUrl(key);
            ossResult.setUrl(downloadUrl);
        }
        return ossResult;
    }
    
    /**
     * 构建 OSS 文件下载 URL
     * @param key 文件 key
     * @return 完整的下载 URL
     */
    private String buildDownloadUrl(String key) {
        log.info("构建图片下载 URL - key: {}", key);
        
        // 使用后端代理 URL，隐藏 OSS 信息
        // 前端通过 /dev-api/image/proxy?key=xxx 访问
        String proxyUrl = String.format("/dev-api/image/proxy?key=%s", key);
        
        log.info("生成的代理 URL: {}", proxyUrl);
        
        return proxyUrl;
    }
}